﻿using FB.Data.Models;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Collections;
using FB.Infrastructure;
using System.Web;
using System.ComponentModel;
using System.Net.Mail;
using System.Diagnostics;
using System.Threading.Tasks;

namespace FB.Services
{
    public class MailService
    {
        //private readonly ISmtpClient _smtpClient;

        string _host;
        System.Net.NetworkCredential _credential;

        public MailService(ISmtpClient smtpClient) {

            var smtp = smtpClient as SmtpClientProxy;
            _host = smtp.SMTPClient.Host;
            _credential = smtp.SMTPClient.Credentials as System.Net.NetworkCredential;
        }


        public void SendEmailNotification<T>(string template, T data) where T : MailDataModel
        {
            var msg = new System.Net.Mail.MailMessage();

            var templatePath = (template.IndexOf(@":\") >= 0) ? template : HttpContext.Current.Server.MapPath(template);

            foreach (var e in data.To)
                msg.To.Add(e);

            if (null != data.Bcc)
            {
                foreach (var b in data.Bcc)
                    msg.Bcc.Add(b);
            }

            msg.Subject = data.Subject;
            msg.IsBodyHtml = data.IsBodyHtml;
            msg.HeadersEncoding = data.BodyEncoding;
            msg.BodyEncoding = data.BodyEncoding;
            msg.Body = ReplaceTokens(LoadTemplate(templatePath, Encoding.UTF8), data);
            msg.From = new System.Net.Mail.MailAddress(data.From);
            msg.Priority = data.Priority;

//#if !DEBUG
            var smtp = new SmtpClient(_host);
            smtp.Credentials = _credential;
            smtp.SendCompleted += new SendCompletedEventHandler(SendNotificationCompletedCallback);
            smtp.SendAsync(msg, data);
//#else
            //Console.WriteLine(msg.Body);
//#endif
        }


        public void SendNotificationCompletedCallback(object sender, AsyncCompletedEventArgs e)
        {
            var EmailData = (MailDataModel)e.UserState;


            if (EmailData != null)
            {
                
                var logger = NLog.LogManager.GetCurrentClassLogger();
                if (null != logger)
                {
                    var LoggingLayout = "[Subject]:{0} | [From]:{1} | [To]:{2} | [Status]:{3}";

                    var Params = new object[]
                    { 
                        EmailData.Subject,
                        EmailData.From,
                        string.Join(",", EmailData.To),
                        e.Cancelled ? "canceled" : (e.Error != null) ? "error" : "success"
                    };

                    if (e.Error != null)
                    {
                        logger.ErrorException(string.Format(LoggingLayout, Params), e.Error);
                    }
                    else
                    {
                        logger.Info(LoggingLayout, Params);
                    }
                }
                
            }
        }


        public string BindingTemplate<T>(string TemplatePath, T data)
        {
            var FilePath = (TemplatePath.IndexOf(@":\") >= 0) ? TemplatePath : HttpContext.Current.Server.MapPath(TemplatePath);

            return ReplaceTokens<T>(LoadTemplate(FilePath, Encoding.UTF8), data);
        }

        
        public string ReplaceTokens<T>(string format, T data)
        {

            var type = typeof(T);
            var result = format;

            foreach (var p in type.GetProperties(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance))
            {
                var val = p.GetValue(data, null);
                if (!p.GetType().IsSubclassOf(typeof(System.Collections.ICollection)))
                {
                    var regex = new System.Text.RegularExpressions.Regex(string.Format(@"(\{{){0}:.*(\}})", p.Name));
                    var stringFormat = string.Empty;

                    if (regex.IsMatch(result))
                    {
                        var matched = regex.Match(result).Value;
                        var startIdx = matched.IndexOf(':');
                        var len = matched.Length;
                        if (startIdx < len - 1)
                        {

                            stringFormat = matched.Substring(startIdx, len - startIdx - 1);
                        }
                    }


                    result = result.Replace(string.Format("{{{0}" + stringFormat + "}}", p.Name),
                        (val == null) ? string.Empty :
                        (string.IsNullOrEmpty(stringFormat)) ? val.ToString() : string.Format("{0" + stringFormat + "}", val));

                }
            }

            return result;
        }



        public string LoadTemplate(string path, Encoding encoding)
        {
            if (string.IsNullOrEmpty(path))
            {
                throw new ArgumentNullException("path");
            }

            if (encoding == null)
            {
                throw new ArgumentNullException("encoding");
            }

            using (var fileStream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read, bufferSize: 0x1000, useAsync: true))
            {
                var sb = new StringBuilder();

                var buffer = new byte[0x1000];
                int numRead;
                //while ((numRead = fileStream.ReadAsync(buffer, 0, buffer.Length).Result) != 0)
                while ((numRead = fileStream.Read(buffer, 0, buffer.Length)) != 0)
                {
                    var text = encoding.GetString(buffer, 0, numRead);
                    sb.Append(text);
                }

                return sb.ToString();
            }
        }

    }
}
